package com.mall.project.sys.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.mall.common.core.asserts.ApiAssert;
import com.mall.common.core.cons.AuthCons;
import com.mall.common.core.cons.StatusCons;
import com.mall.common.core.enums.ErrorCodeEnum;
import com.mall.common.core.model.entity.LoginInfo;
import com.mall.common.redis.utils.RedisUtils;
import com.mall.common.security.prop.TokenProp;
import com.mall.common.security.utils.ApiUtils;
import com.mall.common.security.utils.JWTUtils;
import com.mall.project.sys.model.entity.User;
import com.mall.project.sys.service.ITokenService;
import com.mall.project.sys.service.IUserService;
import org.apache.commons.codec.digest.Md5Crypt;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 登录 服务实现类
 * </p>
 *
 * @author Sam
 * @since 2020-12-27
 */
@Service
public class TokenServiceImpl implements ITokenService {

    @Autowired
    private IUserService userService;
    @Autowired
    private RedisUtils redisUtils;

    @Override
    public String login(String loginName, String password) {
        User user = userService.getOne(Wrappers.<User>lambdaQuery().eq(User::getLoginName, loginName), false);
        ApiAssert.notNull(ErrorCodeEnum.INTERNAL_SERVER_ERROR.convert("用户名密码错误"), user);
        ApiAssert.isTrue(ErrorCodeEnum.INTERNAL_SERVER_ERROR.convert("用户名密码错误"), Md5Crypt.apr1Crypt(password, AuthCons.PASSWORD_SALT).equals(user.getPassword()));
        ApiAssert.isFalse(ErrorCodeEnum.INTERNAL_SERVER_ERROR.convert("用户被禁用"), Objects.equals(StatusCons.DISABLE, user.getStatus()));
        //todo 登录日志
        //token 只存放了用户id 及其他个别信息（不建议放多）
        String token = JWTUtils.generate(user.getId());
        LoginInfo infoDTO = user.convert(LoginInfo.class);
        //存放个人详细信息 刷新token需要重新设置 可以del原数据/也可不del，自动过期
        refreshTokenInfo(token, infoDTO, TokenProp.getRefresh());
        return token;
    }

    @Override
    public void logout(String token) {
        redisUtils.delete(AuthCons.USER_INFO_TOKEN + token);
        redisUtils.delete(AuthCons.USER_REFRESH_TOKEN + token);
    }

    @Override
    public String refresh() {
        String token = ApiUtils.getToken();
        String refreshToken = redisUtils.get(AuthCons.USER_REFRESH_TOKEN + token);
        Long expire = redisUtils.getExpire(AuthCons.USER_REFRESH_TOKEN + token);
        //没有refreshToken或者解析的refreshToken过期了 都要重新登录
        ApiAssert.isFalse(ErrorCodeEnum.UNAUTHORIZED, JWTUtils.isExpired(refreshToken));
        String newToken = JWTUtils.generate(JWTUtils.getUid(token));
        this.refreshTokenInfo(newToken, ApiUtils.loginUser(), expire);
        this.logout(token);
        return newToken;
    }

    @Override
    public void refreshTokenInfo(String token, LoginInfo infoDTO, long expire) {
        infoDTO.setToken(token);
        //存放个人详细信息 刷新token需要重新设置 可以del原数据/也可不del，自动过期
        redisUtils.setEx(AuthCons.USER_INFO_TOKEN + token, JSON.toJSONString(infoDTO), TokenProp.getExpire(), TimeUnit.SECONDS);
        //设置RefreshToken 指定refreshTime时间内，携带有效token 即可延长token时长（返回新token）
        redisUtils.setEx(AuthCons.USER_REFRESH_TOKEN + token, token, expire, TimeUnit.SECONDS);
    }


}
